
from decimal import Decimal, InvalidOperation

from django.core import validators
from django.db import models
from django.utils.functional import cached_property

from .encryptor import aes_encryptor


class BaseEncryptField(object):
    '''
    加密类型的field
    '''

    _prefix = 'ENCRYPTED_'

    def to_python(self, value):
        if value == '':
            return ''

        if isinstance(value, str) and value.startswith(self._prefix):
            return aes_encryptor.decrypt(value[len(self._prefix):])
        return value

    def from_db_value(self, value, *args, **kwargs):
        return self.to_python(value)


class EncryptCharField(BaseEncryptField, models.CharField):

    def get_prep_value(self, value):
        value = super(EncryptCharField, self).get_prep_value(value)
        if not value:
            return value
        value = aes_encryptor.encrypt(value)
        return '%s%s' % (self._prefix, value)


class EncryptTextField(BaseEncryptField, models.TextField):

    def get_prep_value(self, value):
        value = super(EncryptTextField, self).get_prep_value(value)
        if not value:
            return value
        value = aes_encryptor.encrypt(value)
        return '%s%s' % (self._prefix, value)


class EncryptEmailField(BaseEncryptField, models.EmailField):

    def get_prep_value(self, value):
        value = super(EncryptEmailField, self).get_prep_value(value)
        if not value:
            return value
        value = aes_encryptor.encrypt(value)
        return '%s%s' % (self._prefix, value)


class EncryptDecimalValidator(validators.DecimalValidator):

    def __call__(self, value):
        try:
            value = Decimal(value)
        except InvalidOperation:
            raise validators.ValidationError('值`{}`错误，不能转换为decimal类型!'.format(value))
        super(EncryptDecimalValidator, self).__call__(value)

    def __eq__(self, other):
        return True


class EncryptDecimalField(BaseEncryptField, models.CharField):
    empty_strings_allowed = True

    def __init__(self, *args, **kwargs):
        kwargs['max_length'] = 100
        super(EncryptDecimalField, self).__init__(*args, **kwargs)

    def get_prep_value(self, value):
        value = super(EncryptDecimalField, self).get_prep_value(value)
        if value in ('', None):
            return value
        try:
            value = Decimal(value)
        except InvalidOperation:
            raise validators.ValidationError('值`{}`错误，不能转换为decimal类型!'.format(value))
        value = str(format(value, '.2f'))
        value = aes_encryptor.encrypt(value)
        return '%s%s' % (self._prefix, value)

    @cached_property
    def validators(self):
        res = super(EncryptDecimalField, self).validators + [
            EncryptDecimalValidator(10, 2)
        ]
        return res


class EncryptDecimalField2(BaseEncryptField, models.CharField):
    empty_strings_allowed = True

    def __init__(self, *args, **kwargs):
        kwargs['max_length'] = 200
        super(EncryptDecimalField2, self).__init__(*args, **kwargs)

    def get_prep_value(self, value):
        value = super(EncryptDecimalField2, self).get_prep_value(value)
        if value in ('', None):
            return value
        try:
            value = Decimal(value)
        except InvalidOperation:
            raise validators.ValidationError('值`{}`错误，不能转换为decimal类型!'.format(value))
        value = str(format(value, '.3f'))
        value = aes_encryptor.encrypt(value)
        return '%s%s' % (self._prefix, value)

    @cached_property
    def validators(self):
        res = super(EncryptDecimalField2, self).validators + [
            EncryptDecimalValidator(10, 3)
        ]
        return res
